#include "main.h"
#include "Chat.h"

/*
 * Add System Message to Rich Edit
 * Format: === MESSAGE ===
 */
void AddSystemText(HWND hEdit, const char *text)
{
	char *cpyText = (char *)malloc(strlen(text) + 10);
	sprintf(cpyText, "=== %s ===\n", text);
	int nCpyText = strlen(cpyText);

	/* 
	 * Set rich format
	 * + Bold
	 * + Black color
	 * + "System" font
	 */
	CHARFORMAT cfSysText;
	ZeroMemory(&cfSysText, sizeof(CHARFORMAT));
	cfSysText.cbSize = sizeof(CHARFORMAT);
	cfSysText.dwMask = CFM_BOLD | CFM_COLOR;
	cfSysText.dwEffects = CFE_BOLD;
	cfSysText.crTextColor = RGB(0, 0, 0);
	strcpy(cfSysText.szFaceName, "System");

	/*
	 * Insert Text. Looks confusing but not:
	 * 1. Set selection to end (no selection really but places cursor at end of text box)
	 * 2. "Replace" selection with the text
	 * 3. Set selection to what we just added
	 * 4. Apply rich format to selection (so as not to ruin other formatting in box)
	 * 5. Set selection to end again so nothing is selected
	 */
	int nLength = GetWindowTextLength(hEdit);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength);
	SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)cpyText);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength + nCpyText);
	SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfSysText);
	SendMessage(hEdit, EM_SETSEL, nLength + nCpyText, nLength + nCpyText);

	free(cpyText);
}

/*
 * Add Notification
 * Format: !! MESSAGE !!
 */
void AddNotify(HWND hEdit, const char *text, COLORREF crText)
{
	char *cpyText = (char *)malloc(strlen(text) + 8);
	sprintf(cpyText, "!! %s !!\n", text);
	int nCpyText = strlen(cpyText);

	/*
	 * Set rich format:
	 * + Bold
	 * + Color crText (parameter)
	 * + "Verdana" font
	 */
	CHARFORMAT cfSysText;
	ZeroMemory(&cfSysText, sizeof(CHARFORMAT));
	cfSysText.cbSize = sizeof(CHARFORMAT);
	cfSysText.dwMask = CFM_BOLD | CFM_COLOR;
	cfSysText.dwEffects = CFE_BOLD;
	cfSysText.crTextColor = crText;
	strcpy(cfSysText.szFaceName, "Verdana");

	/*
	 * Insert Text. Looks confusing but not:
	 * 1. Set selection to end (no selection really but places cursor at end of text box)
	 * 2. "Replace" selection with the text
	 * 3. Set selection to what we just added
	 * 4. Apply rich format to selection (so as not to ruin other formatting in box)
	 * 5. Set selection to end again so nothing is selected
	 */
	int nLength = GetWindowTextLength(hEdit);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength);
	SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)cpyText);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength + nCpyText);
	SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfSysText);
	SendMessage(hEdit, EM_SETSEL, nLength + nCpyText, nLength + nCpyText);

	free(cpyText);
}

/*
 * Add Chat Msg
 * Format: UserID: MESSAGE
 */
void AddChatMsg(HWND hEdit, const char *szName, COLORREF crText, const char *szMsg)
{
	char *cpyText = (char *)malloc(strlen(szName) + 3);
	sprintf(cpyText, "%s: ", szName);
	int nCpyText = strlen(cpyText);

	/*
	 * Set rich format:
	 * + Bold
	 * + Color crText (parameter)
	 * + "Verdana" font
	 */
	CHARFORMAT cfSysText;
	ZeroMemory(&cfSysText, sizeof(CHARFORMAT));
	cfSysText.cbSize = sizeof(CHARFORMAT);
	cfSysText.dwMask = CFM_BOLD | CFM_COLOR;
	cfSysText.dwEffects = CFE_BOLD;
	cfSysText.crTextColor = crText;
	strcpy(cfSysText.szFaceName, "Verdana");

	/*
	 * Look above (AddNotify) for explanation
	 */
	int nLength = GetWindowTextLength(hEdit);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength);
	SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)cpyText);
	SendMessage(hEdit, EM_SETSEL, nLength, nLength + nCpyText);
	SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfSysText);
	SendMessage(hEdit, EM_SETSEL, nLength + nCpyText, nLength + nCpyText);

	free(cpyText);

	/*
	 * Modify rich format:
	 * + Black font
	 */
	cfSysText.dwMask = CFM_COLOR;
	cfSysText.dwEffects = CFE_BOLD;
	cfSysText.crTextColor = RGB(0, 0, 0);
	strcpy(cfSysText.szFaceName, "Verdana");

	char *szMsgBuf = (char *)malloc(strlen(szMsg) + 2);
	sprintf(szMsgBuf, "%s\n", szMsg);
	int nMsg = strlen(szMsgBuf);

	/*
	 * Look above (AddNotify) for explanation
	 */
	SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)szMsgBuf);
	SendMessage(hEdit, EM_SETSEL, nLength + nCpyText, nLength + nCpyText + nMsg);
	SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfSysText);
	SendMessage(hEdit, EM_SETSEL, nLength + nCpyText + nMsg, nLength + nCpyText + nMsg);

	free(szMsgBuf);
}

/*
 * Send Data
 * Format:	COMM (4 char command)
 *			xxxx (4 char length of data)
 *			data (variable length data)
 * Final example: CONN0010MyUsername
 */
BOOL ChatSend(const char *szCMD, const char *szData, SOCKET s)
{
	int nLength = strlen(szData);
	char *szLength = (char *)malloc(16);

	/*
	 * Convert length to string
	 */
	sprintf(szLength, "%d", nLength);
	if (nLength < 1000)
	{
		/*
		 * Pad beginning of length string with "0"s to 4 characters
		 * example: 10 to 0010
		 */
		while (strlen(szLength) < 4)
		{
			char cBuffer[5];
			sprintf(cBuffer, "0%s", szLength);
			strcpy(szLength, cBuffer);
		}
	}

	nLength += strlen(szLength);

	/*
	 * Send!
	 */
	char *szSend = (char *)malloc(nLength + 5);
	sprintf(szSend, "%s%s%s", szCMD, szLength, szData);
	free(szLength);
	if (!WinsockSend(szSend, s))
	{
		return FALSE;
	}
	free(szSend);

	return TRUE;
}

/*
 * Send Data to All connected users (SERVERS ONLY)
 * Format:	COMM (4 char command)
 *			xxxx (4 char length of data)
 *			data (variable length data)
 * Final example: CONN0010MyUsername
 */
BOOL ChatSendAll(const char *szCMD, const char *szData, int nMaxUsers)
{
	int nLength = strlen(szData);
	char *szLength = (char *)malloc(16);

	/*
	 * Convert length to string
	 */
	sprintf(szLength, "%d", nLength);
	if (nLength < 1000)
	{
		/*
		 * Pad beginning of length string with "0"s to 4 characters
		 * example: 10 to 0010
		 */
		while (strlen(szLength) < 4)
		{
			char cBuffer[5];
			sprintf(cBuffer, "0%s", szLength);
			strcpy(szLength, cBuffer);
		}
	}

	nLength += strlen(szLength);

	/*
	 * Send! (NOTE: This time with WinsockSendAll() which sends to all sockets except 0 (the listening socket))
	 */
	char *szSend = (char *)malloc(nLength + 5);
	sprintf(szSend, "%s%s%s", szCMD, szLength, szData);
	free (szLength);
	if (!WinsockSendAll(szSend, nMaxUsers))
	{
		return FALSE;
	}
	free(szSend);

	return TRUE;
}

/*
 * Send Message Command
 * Format: Same as above but data format different
 * Data Format: name|.|color|.|message
 */
BOOL ChatSendMsg(const char* szName, COLORREF color, const char *szData, int nMaxUsers)
{
	/*
	 * Convert color (DWORD) to string
	 */
	char *szColor = (char *)malloc(16);
	sprintf(szColor, "%d", color);

	int nLength = strlen(szData);
	nLength += strlen(szName);
	nLength += strlen(szColor);
	nLength += 6; // Delimiters

	char *szLength = (char *)malloc(16);

	/*
	 * Convert length to string
	 */
	sprintf(szLength, "%d", nLength);
	if (nLength < 1000)
	{
		/*
		 * Pad beginning of length string with "0"s to 4 characters
		 * example: 10 to 0010
		 */
		while (strlen(szLength) < 4)
		{
			char cBuffer[5];
			sprintf(cBuffer, "0%s", szLength);
			strcpy(szLength, cBuffer);
		}
	}

	nLength += strlen(szLength);

	/*
	 * Send! (Again with WinsockSendAll() (see above))
	 */
	char *szSend = (char *)malloc(nLength + 5);
	sprintf(szSend, "MESG%s%s|.|%s|.|%s", szLength, szName, szColor, szData);
	free (szLength);
	if (!WinsockSendAll(szSend, nMaxUsers))
	{
		return FALSE;
	}
	free(szSend);
	free(szColor);

	return TRUE;
}